package edu.hawaii.ics414.blackjack.card;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * Stores a deck or decks of cards and provides those cards to the table.
 * For convenience, the term used below is always "deck" even if there is more than one involved.
 * 
 * @author Branden Ogata
 *
 */

public class GameDeck
{
  /**
   * The deck of cards.
   * 
   */
  private List<Card> deck;
  
  /**
   * The number of decks.
   * 
   */
  private int numberDecks;
  
  /**
   * Creates a new GameDeck.
   * 
   * @param decks The int indicating the number of decks to create.
   * 
   * @throws IllegalArgumentException Thrown if decks is less than one; 
   *                                  a GameDeck must include at least one deck.
   * 
   */
  
  public GameDeck(int decks) throws IllegalArgumentException
  {
    if (decks < 1)
    {
      throw new IllegalArgumentException("Must have a positive number of decks.");
    }
    else
    {
      this.deck = new LinkedList<Card>();
      this.numberDecks = decks;
      
      // Create decks number of decks
      this.addCards(decks);
    }
  }
  
  /**
   * Adds new cards to this GameDeck.
   * 
   * @param decks The int indicating the number of decks to add to this GameDeck.
   * 
   */
  
  public void addCards(int decks)
  {
    // Create decks number of decks
    for (int i = 0; i < decks; i++)
    {
      // Suit
      for (Suit s : Suit.values())
      {
        // Rank
        for (Rank r : Rank.values())
        {
          this.deck.add(new Card(s, r));
        }
      }
    }
    
    // Shuffle the deck
    shuffle();

  }
  
  /**
   * Shuffles this GameDeck.
   * 
   */
  
  public void shuffle()
  {
    Collections.shuffle(this.deck);
  }
  
  /**
   * Draws a card from this GameDeck.
   * If doing so would result in an empty deck, then add more cards to this GameDeck.
   * 
   * @return The Card that is first in this GameDeck.
   * 
   */
  
  public Card draw()
  {
    // If the size of the deck is one, then removing would leave the deck empty,
    // so it is necessary to add more cards now
    if (this.getSize() == 1)
    {
      this.addCards(this.numberDecks);
    }
    
    return this.deck.remove(0);
  }
  
  /**
   * Looks at the top card in this GameDeck without removing it.
   * Used for the Cheater AI (well, the one that cheats more than the others).
   * 
   * @return The Card that is first in this GameDeck.
   * 
   */
  
  public Card peek()
  {
    return this.deck.get(0);
  }
  
  /**
   * Indicates if this GameDeck is empty.
   * 
   * @return true if this.deck has no cards,
   *         false otherwise.
   *         
   */
  
  public boolean isEmpty()
  {
    return this.deck.isEmpty();
  }
  
  /**
   * Returns the number of cards in this GameDeck.
   * 
   * @return The size of this.deck.
   * 
   */
  
  public int getSize()
  {
    return this.deck.size();
  }
  
  /**
   * Checks if this GameDeck is equal to another object.
   * 
   * @param obj The Object to compare this GameDeck to.
   * 
   * @return isEqual A boolean that is true if this Card is equal to the parameter,
   *                                   false otherwise.
   *                                   
   */
  
  @Override
  public boolean equals(Object obj)
  {
    boolean isEqual = false;
    
    // Check if the parameter is this GameDeck
    if (this == obj)
    {
      isEqual = true;
    }
    // Check if the parameter is a GameDeck
    else if (obj instanceof GameDeck)
    {
      GameDeck temp = (GameDeck) obj;
      
      // Assumes that the Collections equals method will work
      isEqual = this.deck.equals(temp);
    }
    
    return isEqual;
  }
  
  /**
   * Returns a hashcode based on this GameDeck instance.
   * This uses the hashCode method from the Collections API.
   * 
   * @return result An int equal to the hashcode for this GameDeck.
   * 
   */
  
  @Override
  public int hashCode()
  {
    int result = 17;
    int combination = this.deck.hashCode();
        
    return 31 * result + combination;
  }
}
